﻿using System;
using System.Collections.Generic;
#if DEBUG
using System.Diagnostics;
#endif // #if DEBUG
using System.Net;
using System.Xml;
using System.IO;
using System.Text;

using FRL.DebtChased.Extensions;

#if WORKFLOWEDITOR
using System.Windows.Controls;
using FRL.DebtChased.Silverlight.Library;
#endif // #if WORKFLOWEDITOR

#if REPOSITORY
using FRL.DebtChased.Repository;
#endif // #if REPOSITORY

namespace FRL.DebtChased.WorkflowObjects
{

	/// <summary>
	/// Declaration of WorkflowAction_Base class
	/// The base class for all workflow actions
	/// </summary>
	public abstract class WorkflowAction_Base
	{

		/////////////////////////////////////////////////////////////
		// Enumerations

		public enum ePriority
		{
			NotSet = 0,
			Low,
			Medium,
			High,
			Escalating,
			Automated
		}

		/////////////////////////////////////////////////////////////
		// Attributes

		// The day, the offset within the day, and the number of days spanned by the action
		public int Day { get; set; }
		public int Offset { get; set; }
		public int DaySpan { get; set; }

		private ePriority m_Priority = ePriority.NotSet;
		public ePriority Priority
		{
			get { return m_Priority; }
			set { m_Priority = value; }
		}

		// All workflow actions have a unique id, linking them to the clockwork log and account notes
		// and allowing action processing order to be tracked
		private Guid m_guidIdentifier;
		public Guid Identifier
		{
			get { return m_guidIdentifier; }
			set { m_guidIdentifier = value; }
		}

		/////////////////////////////////////////////////////////////
		// Construction

		public WorkflowAction_Base()
		{

			// Initialize member variables
			DaySpan = 1;
			m_guidIdentifier = Guid.NewGuid();

		}

		/////////////////////////////////////////////////////////////
		// Implementation

		// Get the Xml element name
		protected abstract string _getElementName();

		// Get the strings displayed in the boing
#if WORKFLOWEDITOR
		public abstract string GetBoingLabel();
		public abstract string[] GetBoingSubStrings();
#endif // #if WORKFLOWEDITOR

		// Read and write additional action parameters
		protected abstract void _writeParameters(XmlWriter w);
		protected abstract void _readParameters(XmlReader r);

		// Which DebtChased entities are reference by the workflow?
		public virtual void GetObjectsUsed(List<int> iCommBodiesUsed, List<int> iPopupsUsed, List<int> iLetterTypeIds) { }

		// For development use only
#if DEBUG
		public override string ToString()
		{
			return string.Format("{0} Day {1}.{2} DaySpan={3}",
				this.GetType().Name,
				this.Day,
				this.Offset,
				this.DaySpan
			);
		}
#endif // #if DEBUG

		// Get a summary string describing the action
		public abstract string GetSummary( Workflow.eSummaryFormat SummaryFormat );

#if REPOSITORY
		public abstract List<AccountNote> Process(DebtChasedEntities ent, Account acc, AccountInvoice inv);
#endif // #if REPOSITORY

		/////////////////////////////////////////////////////////////
		// Serialization

		public void ToXml(XmlWriter w)
		{

			// Write to xml writer
			w.WriteStartElement(_getElementName());
			{
#if DEBUG
				Debug.Assert(this.Identifier != Guid.Empty);
#endif // #if DEBUG

				// Write the attributes
				w.WriteAttributeString("priority", ((int)m_Priority).ToString());
				w.WriteAttributeString("day", this.Day.ToString());
				w.WriteAttributeString("daySpan", this.DaySpan.ToString());
				w.WriteAttributeString("offset", this.Offset.ToString());
				w.WriteAttributeString("id", this.Identifier.ToString());

				// Write the list of parameters
				_writeParameters(w);

			}
			w.WriteEndElement();

		}

		public bool FromXml(XmlReader r)
		{

			// Declare return variable
			bool bFtmp = true;

			// Read the attributes
			m_Priority = (ePriority) r.SafeReadIntAttribute("priority",(int)ePriority.Low);
			this.Day = r.SafeReadIntAttribute("day", 1);
			this.DaySpan = r.SafeReadIntAttribute("daySpan", 1);
			this.Offset = r.SafeReadIntAttribute("offset", 0);
			this.Identifier = r.SafeReadGuidAttribute("id");

			// If the guid is blank...
			if (this.m_guidIdentifier == Guid.Empty)
			{
#if DEBUG
				Debug.Assert(false);
#endif // #if DEBUG
				this.m_guidIdentifier = Guid.NewGuid();
			}

			// Read the list of parameters
			_readParameters(r);

			// Declare return variable
			return bFtmp;

		}

		/////////////////////////////////////////////////////////////
		// Static Operations

		public static WorkflowAction_Base Clone(WorkflowAction_Base actionSrc, bool bNewIdentifier)
		{

			// Declare return variable
			WorkflowAction_Base Ftmp = null;

			// Create an xml writer with a memory stream
			using (MemoryStream ms = new MemoryStream())
			{

				// Create xml writer
				XmlWriter w = XmlWriter.Create(ms, FRL.DebtChased.Extensions.Extensions.GetXmlWriterSettings());

				// Serialize the source action
				w.WriteStartDocument();
				{
					actionSrc.ToXml(w);
				}
				w.WriteEndDocument();

				// Flush the stream
				w.Flush();
				ms.Flush();
				ms.Position = 0;

				// Open an xml reader
				XmlReader r = XmlReader.Create(ms, FRL.DebtChased.Extensions.Extensions.GetXmlReaderSettings());

				// Loop to the first element
				while (r.Read())
				{

					// If this is an element...
					if (r.NodeType == XmlNodeType.Element)
					{

						// Read action and break out of loop
						Ftmp = WorkflowAction_Base.ConstructorFactory(r.Name);
						if (!Ftmp.FromXml(r))
							Ftmp = null;
						break;

					}

				} // while-loop

			}

			// If that worked and changing the id...
			if ((Ftmp != null) && (bNewIdentifier))
				Ftmp.m_guidIdentifier = Guid.NewGuid();

			// Return variable
			return Ftmp;

		}

		public static WorkflowAction_Base ConstructorFactory(string strElementName)
		{

			// Declare return variable
			WorkflowAction_Base Ftmp = null;

			// Compare names
			if (strElementName == WorkflowAction_PhoneCall.XmlElementName)
				Ftmp = new WorkflowAction_PhoneCall();
			else if (strElementName == WorkflowAction_NotifyManager.XmlElementName)
				Ftmp = new WorkflowAction_NotifyManager();
			else if (strElementName == WorkflowAction_Popup.XmlElementName)
				Ftmp = new WorkflowAction_Popup();
			else if (strElementName == WorkflowAction_Search.XmlElementName)
				Ftmp = new WorkflowAction_Search();
			else if (strElementName == WorkflowAction_SendEmail.XmlElementName)
				Ftmp = new WorkflowAction_SendEmail();
			else if (strElementName == WorkflowAction_SendLetterFax.XmlElementName)
				Ftmp = new WorkflowAction_SendLetterFax();
			else if (strElementName == WorkflowAction_SendSMS.XmlElementName)
				Ftmp = new WorkflowAction_SendSMS();
			else if (strElementName == WorkflowAction_Manual.XmlElementName)
				Ftmp = new WorkflowAction_Manual();
			else
			{
#if DEBUG
				Debug.Assert(false);
#endif // #if DEBUG
			}

			// Return variable
			return Ftmp;

		}

#if WORKFLOWEDITOR
		public static void LoadPriorityDropDown(ComboBox cboPriority, WorkflowAction_Base.ePriority Priority)
		{

			// Load the combo
			cboPriority.Items.Add(new ComboBoxObject("Low / Grade 3", (int)WorkflowAction_Base.ePriority.Low, null));
			cboPriority.Items.Add(new ComboBoxObject("Medium / Grade 2", (int)WorkflowAction_Base.ePriority.Medium, null));
			cboPriority.Items.Add(new ComboBoxObject("High / Grade 1", (int)WorkflowAction_Base.ePriority.High, null));
			cboPriority.Items.Add(new ComboBoxObject("Escalating", (int)WorkflowAction_Base.ePriority.Escalating, null));

			// Select item
			ComboBoxObject.SelectByItemData(cboPriority, (int)Priority);

		}
#endif // #if WORKFLOWEDITOR

	}

}
